﻿// (c) Copyright Damian Mehers http://damianblog.com/
// This source is subject to the Microsoft Public License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

using System;
using System.Diagnostics;
using System.Net;
using System.Threading;

namespace MceFM.Last {
  /// <summary>
  /// Handles a specific HTTP connection from a client.  It streams a single track to the client.
  /// </summary>
  internal class ConnectionHandler {
    private readonly HttpListenerContext context;
    private readonly Track track;

    private static int activeCount;

    public ConnectionHandler(Track track, HttpListenerContext context) {
      this.track = track;
      this.context = context;
    }

    public static int ActiveCount {
      get {return activeCount;}
    }

    public void Start() {
      Thread thread = new Thread(ThreadEntry);
      thread.IsBackground = true;
      thread.Start();
    }


    private void ThreadEntry() {
      int tid = Thread.CurrentThread.ManagedThreadId;

      try {
        Interlocked.Increment(ref activeCount);
        ID3TagManager tagManager = new ID3TagManager(track, true);


        context.Response.Headers[HttpResponseHeader.CacheControl] = "no-cache, must-revalidate";
        context.Response.Headers[HttpResponseHeader.ContentType] = "audio/mpeg";

        if (track.DownloadError) {
          Trace.TraceInformation("ConnectionHandler: Track {0} had a download error, so responding with blank mp3", track);
          SendBlankTrack(tagManager);
          return;
        }

        int contentLength = track.ContentLength;
        if (contentLength == -1)
        {
          contentLength = track.WaitForContent(contentLength);
        }

        tagManager.AddTags();
        byte[] tagsBuffer = tagManager.GetBuffer();

        context.Response.ContentLength64 = tagsBuffer.Length + track.Content.Length;

        Trace.TraceInformation("{0}: Sent mp3 tags for {1} (content length is {2}", tid, track.Title, context.Response.ContentLength64);

        int oldContentLength = 0;
        while(oldContentLength != track.Content.Length && !track.DownloadError) {
          if (tagsBuffer != null) {
            context.Response.OutputStream.Write(tagsBuffer, 0, tagsBuffer.Length);
            tagsBuffer = null;
          }
          context.Response.OutputStream.Write(track.Content, oldContentLength, contentLength - oldContentLength);
          oldContentLength = contentLength;
//          Trace.TraceInformation("{0}: ConnectionHandler: sent {1}/{2} of {3}", tid, contentLength, track.Content.Length, track.Title);
          contentLength = track.WaitForContent(oldContentLength);
        }

        Trace.TraceInformation("{0}: Finished sending lastFM content for {1}.  Sent {2} bytes. DownloadError={3}", tid, track.Title, contentLength, track.DownloadError);
        context.Response.OutputStream.Close();
      } catch(Exception ex) {
        Trace.TraceError("{0}: Error sending content: {1} for {2} ", tid, ex.Message, track.Title);
        Trace.TraceError(ex.StackTrace);
        context.Response.Abort();
      } finally {
        Interlocked.Decrement(ref activeCount);
      }
    }

    private void SendBlankTrack(ID3TagManager tagManager) {
      tagManager.AddTags("Play interrupted", "Cannot resume", "Interrupted play");
      byte[] errorTagsBuffer = tagManager.GetBuffer();
      context.Response.ContentLength64 = errorTagsBuffer.Length + Resources.blank.Length;
      context.Response.OutputStream.Write(errorTagsBuffer, 0, errorTagsBuffer.Length);
      context.Response.OutputStream.Write(Resources.blank, 0, Resources.blank.Length);
      context.Response.OutputStream.Flush();
      context.Response.OutputStream.Close();
    }
  }
}